#include "configgroup.h"
#include "variant.h"
#include "config.h"

using namespace std;

ConfigGroup::ConfigGroup(Config& parent, const string& groupName)
    : m_config(parent), m_parent(0), m_name(groupName),
    m_exists(false), m_groups( *new map<string, ConfigGroup*>() ),
    m_entries( *new map<string, Variant*>() )
{
}

ConfigGroup::ConfigGroup(ConfigGroup& parent, const string& groupName)
    : m_config(parent.m_config), m_parent(&parent), m_name(groupName),
    m_exists(false), m_groups( *new map<string, ConfigGroup*>() ),
    m_entries( *new map<string, Variant*>() )
{
}

ConfigGroup::~ConfigGroup()
{
    map<string, ConfigGroup*>::iterator it = m_groups.begin();
    for(; it != m_groups.end(); it++)
    {
        delete it->second;
    }
    
    map<string, Variant*>::iterator it2 = m_entries.begin();
    for(; it2 != m_entries.end(); it2++)
    {
        delete it2->second;
    }
}

bool ConfigGroup::exists()
{
    return !isEmpty() || m_exists;
}

bool ConfigGroup::isEmpty()
{
    // Return true if any of the subgroups is not empty
    map<string, ConfigGroup*>::iterator it = m_groups.begin();
    for(; it != m_groups.end(); it++)
    {
        if(!it->second->isEmpty())
            return false;
    }
    
    return m_entries.empty();
}

string ConfigGroup::name()
{
    return m_name;
}

ConfigGroup* ConfigGroup::parent()
{
    return m_parent;
}

Config& ConfigGroup::config()
{
    return m_config;
}

list<string> ConfigGroup::keyList()
{
    list<string> retList;
    map<string, Variant*>::iterator it = m_entries.begin();
    for(; it != m_entries.end(); it++)
    {
        retList.push_back(it->first);
    }
    
    return retList;
}

bool ConfigGroup::hasGroup(const string& name)
{
    map<string, ConfigGroup*>::iterator it =  m_groups.find(name);
    if(it == m_groups.end())
        return false;
    else
        return it->second->exists();
}

void ConfigGroup::deleteGroup(const string& name)
{
    m_groups[name]->deleteAll();
}

void ConfigGroup::deleteAll()
{
    //First remove all entries of this group
    map<string, Variant*>::iterator it = m_entries.begin();
    for(; it != m_entries.end(); it++)
    {
        delete it->second;
        m_entries.erase(it);
    }
    
    // Recursively delete all subgroups
    map<string, ConfigGroup*>::iterator it2 = m_groups.begin();
    for(; it2 != m_groups.end(); it2++)
    {
        it2->second->deleteAll();
    }
    
    //Finally set it as deleted
    m_exists = false;
}

list<string> ConfigGroup::groupList()
{
    list<string> retList;
    map<string, ConfigGroup*>::iterator it = m_groups.begin();
    for(; it != m_groups.end(); it++)
    {
        retList.push_back(it->first);
    }
    
    return retList;
}

bool ConfigGroup::hasKey(const string& key)
{
    return m_entries.find(key) != m_entries.end();
}

void ConfigGroup::deleteEntry(const string& name)
{
    m_entries.erase(m_entries.find(name));
}

map<string, Variant*>& ConfigGroup::entryMap()
{
    return m_entries;
}

ConfigGroup& ConfigGroup::operator[](const string& groupName)
{
    map<string, ConfigGroup*>::iterator it =  m_groups.find(groupName);
    if(it == m_groups.end())
    {
        ConfigGroup* cg = new ConfigGroup(*this, groupName);
        cg->m_exists = false;
        m_groups[groupName] = cg;
        return *cg;
    } else
        return *m_groups[groupName];
}

void ConfigGroup::sync(fstream& istream)
{
    list<string> pathList;
    pathList.push_front(m_name);
    
    // First write the header
    for(ConfigGroup *item = m_parent; item != 0; item = item->m_parent)
    {
        pathList.push_front(item->m_name);
    }
    
    list<string>::iterator it = pathList.begin();
    for(; it != pathList.end(); it++)
    {
        istream << "[" << *it << "]";
    }
    istream << endl;
    
    // Then write the entries
    map<string, Variant*>::iterator it2 = m_entries.begin();
    for(; it2 != m_entries.end(); it2++)
    {
        istream << it2->first << "=" << it2->second->tokenize() << endl;
    }
    istream << endl;
    
    // And finally let the subgroups write themselves to disc
    map<string, ConfigGroup*>::iterator it3 = m_groups.begin();
    for(; it3 != m_groups.end(); it3++)
    {
        it3->second->sync(istream);
    }
}

int ConfigGroup::readEntry(const string& key, const int& aDefault)
{
    map<string, Variant*>::iterator it = m_entries.find(key);
    if(it == m_entries.end())
        return aDefault;
    else
    {
        Variant* variant = it->second;
        // By default all entries are stored as a string, so if it's still a
        // string now it's the time to change that.
        if(variant->type() == Variant::String)
        {
            int value = Variant::parseTokens(variant->toString(), Variant::Int).toInt();
            m_entries[key] = new Variant(value);
            // delete the old variant
            delete variant;
            
            return value;
        } else
            return variant->toInt();
    }
}

float ConfigGroup::readEntry(const string& key, const float& aDefault)
{
    map<string, Variant*>::iterator it = m_entries.find(key);
    if(it == m_entries.end())
        return aDefault;
    else
    {
        Variant* variant = it->second;
        // By default all entries are stored as a string, so if it's still a
        // string now it's the time to change that.
        if(variant->type() == Variant::String)
        {
            float value = Variant::parseTokens(variant->toString(), Variant::Float).toFloat();
            m_entries[key] = new Variant(value);
            // delete the old variant
            delete variant;
            
            return value;
        } else
            return variant->toFloat();
    }
}


string ConfigGroup::readEntry(const string& key, const string& aDefault)
{
    map<string, Variant*>::iterator it = m_entries.find(key);
    if(it == m_entries.end())
        return aDefault;
    else
    {
        Variant* variant = it->second;
        
        if(variant->tokenized())
        {
            // Untokenize the string
            string value = Variant::parseTokens(variant->toString(), Variant::String).toString();
            m_entries[key] = new Variant(value);
            m_entries[key]->setTokenized(false);
            // delete the old variant
            delete variant;
            
            return value;
        } else
            return variant->toString();
    }
}


vector<int> ConfigGroup::readEntry(const string& key, const vector<int>& aDefault)
{
    
    map<string, Variant*>::iterator it = m_entries.find(key);
    if(it == m_entries.end())
        return aDefault;
    else
    {
        Variant* variant = it->second;
        // By default all entries are stored as a string, so if it's still a
        // string now it's the time to change that.
        if(variant->type() == Variant::String)
        {
            vector<int> value = Variant::parseTokens(variant->toString(), Variant::IntVector).toIntVector();
            m_entries[key] = new Variant(value);
            // delete the old variant
            delete variant;
            
            return value;
        } else
            return variant->toIntVector();
    }
}


vector<float> ConfigGroup::readEntry(const string& key, const vector<float>& aDefault)
{
    
    map<string, Variant*>::iterator it = m_entries.find(key);
    if(it == m_entries.end())
        return aDefault;
    else
    {
        Variant* variant = it->second;
        // By default all entries are stored as a string, so if it's still a
        // string now it's the time to change that.
        if(variant->type() == Variant::String)
        {
            vector<float> value = Variant::parseTokens(variant->toString(), Variant::FloatVector).toFloatVector();
            m_entries[key] = new Variant(value);
            // delete the old variant
            delete variant;
            
            return value;
        } else
            return variant->toFloatVector();
    }
}


vector<string> ConfigGroup::readEntry(const string& key, const vector<string>& aDefault)
{
    
    map<string, Variant*>::iterator it = m_entries.find(key);
    if(it == m_entries.end())
        return aDefault;
    else
    {
        Variant* variant = it->second;
        // By default all entries are stored as a string, so if it's still a
        // string now it's the time to change that.
        if(variant->type() == Variant::String)
        {
            vector<string> value = Variant::parseTokens(variant->toString(), Variant::StringVector).toStringVector();
            m_entries[key] = new Variant(value);
            // delete the old variant
            delete variant;
            
            return value;
        } else
            return variant->toStringVector();
    }
}

void ConfigGroup::writeEntry(const string& key, const int& value)
{
    map<string, Variant*>::iterator it = m_entries.find(key);
    if(it == m_entries.end())
    {
        m_entries[key] = new Variant(value);
    } else
    {
        delete it->second;
        m_entries[key] = new Variant(value);
    }
}

void ConfigGroup::writeEntry(const string& key, const float& value)
{
    map<string, Variant*>::iterator it = m_entries.find(key);
    if(it == m_entries.end())
    {
        m_entries[key] = new Variant(value);
    } else
    {
        delete it->second;
        m_entries[key] = new Variant(value);
    }
}

void ConfigGroup::writeEntry(const string& key, const string& value)
{
    map<string, Variant*>::iterator it = m_entries.find(key);
    if(it == m_entries.end())
    {
        m_entries[key] = new Variant(value);
        m_entries[key]->setTokenized(false);
    }
    else
    {
        delete it->second;
        m_entries[key] = new Variant(value);
        m_entries[key]->setTokenized(false);
    }
}

void ConfigGroup::writeEntry(const string& key, const vector<int>& value)
{
    map<string, Variant*>::iterator it = m_entries.find(key);
    if(it == m_entries.end())
    {
        m_entries[key] = new Variant(value);
        m_entries[key]->setTokenized(false);
    }
    else
    {
        delete it->second;
        m_entries[key] = new Variant(value);
        m_entries[key]->setTokenized(false);
    }
}

void ConfigGroup::writeEntry(const string& key, const vector<float>& value)
{
    map<string, Variant*>::iterator it = m_entries.find(key);
    if(it == m_entries.end())
    {
        m_entries[key] = new Variant(value);
    }
    else
    {
        delete it->second;
        m_entries[key] = new Variant(value);
    }
}

void ConfigGroup::writeEntry(const string& key, const vector<string>& value)
{
    map<string, Variant*>::iterator it = m_entries.find(key);
    if(it == m_entries.end())
    {
        m_entries[key] = new Variant(value);
    }
		else
    {
        delete it->second;
        m_entries[key] = new Variant(value);
    }
}
